package org.hismig.view;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.ToolTipManager;
import javax.swing.WindowConstants;
import javax.swing.border.BevelBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

import org.hismig.cfg.Configuration;
import org.hismig.migration.Context;
import org.hismig.migration.HisMigConsole;
import org.hismig.migration.executor.DBExecutor;
import org.hismig.migration.executor.DBExecutorBase;
import org.hismig.migration.executor.DBExecutorListenerAdapter;
import org.hismig.migration.executor.TableExecutor;
import org.hismig.migration.executor.TableExecutorBase;
import org.hismig.migration.executor.TableExecutorListenerAdapter;
import org.hismig.migration.executor.ext.IExtExecutor;
import org.hismig.migration.result.DBResultInfo;
import org.hismig.migration.result.JobResultInfo;
import org.hismig.migration.result.ResultInfo;
import org.hismig.migration.result.RunResultInfo;
import org.hismig.migration.result.TableResultInfo;
import org.hismig.report.JobResultReport;
import org.hismig.scheduler.ITrigger;
import org.hismig.scheduler.ITriggerListener;
import org.hismig.utils.DateTool;

/**
 * @declare: //TODO <br />
 *           This class created by Vansion.Hopihit on 2012-8-8 <br />
 *           <a href="mailto:vansionhopihit@gmail.com">Contact Me</a>
 * @version 1.0
 * @author Vansion.Hopihit
 * 
 */
public class MainFrame extends JFrame implements ITriggerListener {

	private static final long serialVersionUID = 8845411470467761017L;

	public static final int STATUS_FREE = 0;
	public static final int STATUS_RUNNING = 1;
	public static final int STATUS_STOP = 2;

	private JPanel contentPane;
	private JTable jobTab;
	private JLabel lab_status;
	private JLabel lab_msg;
	private JProgressBar progressBar;

	private JTree resultTree;
	private DefaultMutableTreeNode root;

	private ITrigger trigger;

	private TrayIcon trayIcon;

	private boolean isRuning;
	private boolean isShutdown;

	private Font commonFont;
	private Font resultFont;

	private RunResultInfo runResultInfo = new RunResultInfo();

	private Icon systemIcon;

	public void start() {
		setVisible(true);
	}

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		new MainFrame(null).start();
	}

	/**
	 * Create the frame.
	 */
	public MainFrame(final ITrigger trigger) {
		this.trigger = trigger;

		initMenuItems();
		initIcons();

		setTitle("HisMig - Console");
		setResizable(false);
		setIconImage(Toolkit.getDefaultToolkit().getImage(
				getClass().getResource("logo_16.png")));
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 496, 540);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(null);

		setContentPane(contentPane);

		JScrollPane jobPanel = new JScrollPane();
		jobPanel.setBounds(6, 120, 478, 59);
		contentPane.add(jobPanel);

		jobTab = new JTable();
		jobTab.setFont(getCommonFont());
		// jobTab.setBorder(new LineBorder(new Color(0, 0, 0)));
		jobTab.setRowHeight(20);

		jobTab.setModel(new JobTableModel(trigger));
		jobTab.getColumn(jobTab.getColumnName(0)).setPreferredWidth(60);
		jobTab.getColumn(jobTab.getColumnName(1)).setPreferredWidth(80);
		jobTab.getColumn(jobTab.getColumnName(2)).setPreferredWidth(80);

		jobPanel.setViewportView(jobTab);

		JPanel msgPanel = new JPanel();
		msgPanel.setBorder(new TitledBorder(new EtchedBorder(
				EtchedBorder.LOWERED, null, null), "Message",
				TitledBorder.LEADING, TitledBorder.TOP, null, new Color(59, 59,
						59)));
		msgPanel.setBounds(6, 6, 478, 102);
		contentPane.add(msgPanel);
		msgPanel.setLayout(null);

		JLabel labs_status = new JLabel("运行状态:");
		labs_status.setBounds(80, 25, 65, 18);
		labs_status.setFont(getCommonFont());

		msgPanel.add(labs_status);

		lab_status = new JLabel("空闲中...");
		lab_status.setBounds(155, 25, 70, 18);

		lab_status.setFont(getCommonFont());
		msgPanel.add(lab_status);

		progressBar = new JProgressBar();
		progressBar.setBounds(80, 50, 376, 25);

		// show the value
		progressBar.setStringPainted(true);

		msgPanel.add(progressBar);

		JLabel lab_logo = new JLabel();

		lab_logo.setIcon(new ImageIcon(Toolkit.getDefaultToolkit().getImage(
				getClass().getResource("logo_48.png"))));
		lab_logo.setBounds(15, 30, 48, 48);
		lab_logo.setToolTipText(getVersionInfo());

		msgPanel.add(lab_logo);

		lab_msg = new JLabel();
		lab_msg.setFont(getResultFont());
		lab_msg.setBounds(80, 78, 376, 18);
		msgPanel.add(lab_msg);

		final JButton btn_start = new JButton();
		btn_start.setToolTipText("开始运行");
		btn_start.setIcon(new ImageIcon(Toolkit.getDefaultToolkit().getImage(
				getClass().getResource("start_32.png"))));
		btn_start.setBounds(230, 25, 24, 24);
		btn_start.setBorder(BorderFactory
				.createBevelBorder(BevelBorder.LOWERED));
		btn_start.setEnabled(false);
		msgPanel.add(btn_start);

		final JButton btn_stop = new JButton();
		btn_stop.setToolTipText("停止运行");
		btn_stop.setIcon(new ImageIcon(Toolkit.getDefaultToolkit().getImage(
				getClass().getResource("stop_32.png"))));
		btn_stop.setBounds(270, 25, 24, 24);
		btn_stop.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
		if (null == trigger) {
			btn_stop.setEnabled(false);
		}

		msgPanel.add(btn_stop);

		btn_start.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				btn_start.setEnabled(false);
				btn_stop.setEnabled(true);

				btn_start.setBorder(BorderFactory
						.createBevelBorder(BevelBorder.LOWERED));
				btn_stop.setBorder(BorderFactory
						.createBevelBorder(BevelBorder.RAISED));

				isShutdown = false;

				trigger.resume();
				changeStatus(STATUS_FREE);
			}
		});

		btn_stop.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (isRuning) {
					JOptionPane.showMessageDialog(MainFrame.this, "正在执行，无法停止",
							"无法退出", JOptionPane.WARNING_MESSAGE, systemIcon);

					return;
				}

				btn_stop.setEnabled(false);
				btn_start.setEnabled(true);

				btn_start.setBorder(BorderFactory
						.createBevelBorder(BevelBorder.RAISED));
				btn_stop.setBorder(BorderFactory
						.createBevelBorder(BevelBorder.LOWERED));

				trigger.pause();
				isShutdown = true;

				changeStatus(STATUS_STOP);

			}
		});

		JScrollPane resultPanel = new JScrollPane();
		resultPanel.setBounds(6, 208, 478, 252);
		contentPane.add(resultPanel);

		root = new DefaultMutableTreeNode(runResultInfo);

		resultTree = new JTree(root);

		// Enable tool tips.
		ToolTipManager.sharedInstance().registerComponent(resultTree);

		resultTree.setFont(getResultFont());

		resultTree.setCellRenderer(new ResultTreeCellRenderer());

		// add mouse menu
		resultTree.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseReleased(MouseEvent e) {
				super.mouseReleased(e);

				if (e.isPopupTrigger()) {

					JTree tree = (JTree) e.getComponent();
					TreePath path = tree.getPathForLocation(e.getX(), e.getY());

					tree.setSelectionPath(path);

					Object node = tree.getLastSelectedPathComponent();

					JPopupMenu popupMenu = new JPopupMenu();
					viewMenuItem.setEnabled(false);
					popupMenu.add(clearMenuItem);
					popupMenu.add(viewMenuItem);

					if (null != node) {
						if (node instanceof DefaultMutableTreeNode) {

							if (((DefaultMutableTreeNode) node).getUserObject() instanceof RunResultInfo) {
							} else {
								viewMenuItem.setEnabled(true);
							}

						}

					}
					popupMenu.show(tree, e.getX(), e.getY());

				}
			}

		});

		resultPanel.setViewportView(resultTree);

		JButton btnExit = new JButton("退出", new ImageIcon(Toolkit
				.getDefaultToolkit().getImage(
						getClass().getResource("exit.png"))));
		btnExit.setFont(getCommonFont());
		btnExit.setBounds(394, 472, 90, 30);
		btnExit.setToolTipText("安全退出");
		btnExit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				if (isRuning) {
					JOptionPane.showMessageDialog(MainFrame.this,
							"正在执行，请先停止再退出", "无法退出",
							JOptionPane.WARNING_MESSAGE, systemIcon);

					return;
				}

				exit();
			}

		});
		contentPane.add(btnExit);

		JButton btnEncrypt = new JButton("");
		btnEncrypt.setIcon(new ImageIcon(Toolkit.getDefaultToolkit().getImage(
				getClass().getResource("encrypt_32.png"))));
		btnEncrypt.setBounds(6, 465, 24, 24);
		btnEncrypt.setToolTipText("加密配置文件");
		btnEncrypt.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				String fileName = HisMigConsole.getInstance().getFileName();

				int ret = JOptionPane.showConfirmDialog(MainFrame.this,
						String.format("您是否确认加密配置文件（%s）？", fileName),
						"加密确认（不可逆）", JOptionPane.YES_NO_OPTION,
						JOptionPane.INFORMATION_MESSAGE, systemIcon);

				if (JOptionPane.YES_OPTION == ret) {
					try {
						Configuration configuration = new Configuration(
								fileName);
						configuration.encryptCfg();
						JOptionPane.showMessageDialog(MainFrame.this,
								String.format("加密配置文件（%s）完成 :-)", fileName),
								"加密配置文件", JOptionPane.INFORMATION_MESSAGE,
								systemIcon);
					} catch (Throwable t) {
						JOptionPane.showMessageDialog(MainFrame.this, String
								.format("加密配置文件（%s）失败:\n%s", new Object[]{
										fileName, t.getMessage()}), "加密配置文件",
								JOptionPane.ERROR_MESSAGE, systemIcon);
						t.printStackTrace();
					}
				}
			}
		});
		contentPane.add(btnEncrypt);

		initTrayIcon();

		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				exit();
			}

			@Override
			public void windowIconified(WindowEvent e) {
				if (SystemTray.isSupported()) {
					setVisible(false);
					minimizeToTray();
				} else {
					super.windowIconified(e);
				}
			}
		});

	}

	private String getVersionInfo() {

		return "<html><Strong>HisMigControl</Strong> - Verison:0.9<p></p><font color='blue'>Designed by Vansion</font></html>";

	}

	@Override
	public void beforeTriggerStart(Context context, List<DBExecutor> dbExecutors) {
		changeStatus(STATUS_RUNNING);

		isRuning = true;
		setTrayToolTipText();

		progressBar.setMinimum(0);
		progressBar.setForeground(Color.GRAY);

		int taskCount = 0;

		for (DBExecutor dbExecutor : dbExecutors) {

			taskCount += dbExecutor.getExtExecutorCount();
			taskCount += dbExecutor.getTableExecutorCount();

			dbExecutor.addListener(new DBExecutorListenerAdapter() {
				@Override
				public void beforeDBExecuteStart(Context context,
						DBExecutorBase dbExecutorBase) {
					lab_msg.setText(String.format("正在执行数据库[%s]迁移",
							dbExecutorBase.getDataBase().getName()));
				}

				@Override
				public void beforeExtExecuteStart(Context context,
						IExtExecutor extExecutor) {
					lab_msg.setText(String.format("正在执行数据库运行脚本 - %s",
							extExecutor.getExtExecutor().getParent()));
				}

				@Override
				public void afterExtExecuteEnd(ResultInfo resultInfo) {
					// lab_status.setText("finish extExecutor with "
					// + resultInfo.getName());

					progressBar.setValue(progressBar.getValue() + 1);
				}

				@Override
				public void beforeTableExecuteStart(Context context,
						TableExecutorBase tableExecutorBase) {
					lab_msg.setText(String.format("正在执行表[%s]迁移",
							tableExecutorBase.getTable().getName()));
				}

				@Override
				public void afterTableExecuteEnd(TableResultInfo tableResultInfo) {
					// lab_status.setText("finish tableExecutor with "
					// + tableResultInfo.getName());

					progressBar.setValue(progressBar.getValue() + 1);
				}

				@Override
				public void afterDBExecuteEnd(DBResultInfo dbResultInfo) {
					// lab_status.setText("finish deExecutor "
					// + dbResultInfo.getName());
				}
			});

			for (TableExecutor tableExecutor : dbExecutor.getTableExecutors()) {

				taskCount += tableExecutor.getExtExecutorCount();

				tableExecutor.addListener(new TableExecutorListenerAdapter() {

					@Override
					public void beforeExtExecuteStart(Context context,
							IExtExecutor extExecutor) {
						lab_msg.setText(String.format("正在执行表运行脚本 - %s",
								extExecutor.getExtExecutor().getParent()));
					}

					@Override
					public void afterExtExecuteEnd(ResultInfo resultInfo) {
						// lab_status.setText("finish extExecutor with "
						// + resultInfo.getName());

						progressBar.setValue(progressBar.getValue() + 1);
					}

				});

			}

			progressBar.setMaximum(taskCount);
		}

	}

	private Font getCommonFont() {
		if (null == commonFont) {
			commonFont = new Font("宋体", Font.BOLD, 13);
		}

		return commonFont;
	}

	private Font getResultFont() {
		if (null == resultFont) {
			resultFont = new Font("宋体", Font.PLAIN, 12);
		}

		return resultFont;
	}

	@Override
	public void afterTriggerEnd(JobResultInfo jobResultInfo) {
		lab_msg.setText(String.format("调度执行完毕，耗时：%sms",
				jobResultInfo.getExecuteTime()));

		runResultInfo.addRunCount();
		if (0 == jobResultInfo.getErrorCount()) {
			progressBar.setForeground(Color.GREEN);
		} else {
			progressBar.setForeground(Color.RED);
			runResultInfo.addErrorCount();
		}

		DefaultMutableTreeNode jobNode = new DefaultMutableTreeNode(
				jobResultInfo);

		for (DBResultInfo dbResultInfo : jobResultInfo.getDbResultInfos()) {

			DefaultMutableTreeNode dbNode = new DefaultMutableTreeNode(
					dbResultInfo);

			if (null != dbResultInfo.getSourcePreResultInfo()) {
				DefaultMutableTreeNode extExecutorNode = new DefaultMutableTreeNode(
						dbResultInfo.getSourcePreResultInfo());
				dbNode.add(extExecutorNode);
			}
			if (null != dbResultInfo.getDistPreResultInfo()) {
				DefaultMutableTreeNode extExecutorNode = new DefaultMutableTreeNode(
						dbResultInfo.getDistPreResultInfo());
				dbNode.add(extExecutorNode);
			}

			for (TableResultInfo tableResultInfo : dbResultInfo
					.getTableResultInfos()) {

				DefaultMutableTreeNode tableNode = new DefaultMutableTreeNode(
						tableResultInfo);

				if (null != tableResultInfo.getSourcePreResultInfo()) {
					DefaultMutableTreeNode extExecutorNode = new DefaultMutableTreeNode(
							tableResultInfo.getSourcePreResultInfo());
					tableNode.add(extExecutorNode);
				}
				if (null != tableResultInfo.getDistPreResultInfo()) {
					DefaultMutableTreeNode extExecutorNode = new DefaultMutableTreeNode(
							tableResultInfo.getDistPreResultInfo());
					tableNode.add(extExecutorNode);
				}

				if (null != tableResultInfo.getExecuteResultInfo()) {
					DefaultMutableTreeNode executorNode = new DefaultMutableTreeNode(
							tableResultInfo.getExecuteResultInfo());
					tableNode.add(executorNode);
				}

				if (null != tableResultInfo.getDistAfterResultInfo()) {
					DefaultMutableTreeNode extExecutorNode = new DefaultMutableTreeNode(
							tableResultInfo.getDistAfterResultInfo());
					tableNode.add(extExecutorNode);
				}
				if (null != tableResultInfo.getSourceAfterResultInfo()) {
					DefaultMutableTreeNode extExecutorNode = new DefaultMutableTreeNode(
							tableResultInfo.getSourceAfterResultInfo());
					tableNode.add(extExecutorNode);
				}

				dbNode.add(tableNode);
			}

			if (null != dbResultInfo.getDistAfterResultInfo()) {
				DefaultMutableTreeNode extExecutorNode = new DefaultMutableTreeNode(
						dbResultInfo.getDistAfterResultInfo());
				dbNode.add(extExecutorNode);
			}
			if (null != dbResultInfo.getSourceAfterResultInfo()) {
				DefaultMutableTreeNode extExecutorNode = new DefaultMutableTreeNode(
						dbResultInfo.getSourceAfterResultInfo());
				dbNode.add(extExecutorNode);
			}

			jobNode.add(dbNode);
		}

		root.add(jobNode);

		resultTree.updateUI();

		isRuning = false;
		setTrayToolTipText();

		if (isShutdown) {
			changeStatus(STATUS_STOP);
		} else {
			changeStatus(STATUS_FREE);
		}
	}

	private void minimizeToTray() {
		SystemTray tray = SystemTray.getSystemTray();

		setTrayToolTipText();

		try {
			tray.add(this.trayIcon);
		} catch (AWTException ex) {
			ex.printStackTrace();
		}
	}

	private void setTrayToolTipText() {
		if (isRuning) {
			trayIcon.setToolTip("正在执行调度...");
		} else {
			if (null != trigger) {
				trayIcon.setToolTip(String.format("下次调度: %s",
						DateTool.getNormalDateTime(trigger.getNextFireTime())));
			} else {
				trayIcon.setToolTip(String.format("下次调度: %s",
						"2000-01-01 00:00:00"));
			}

		}
	}

	private void initTrayIcon() {
		Image image = Toolkit.getDefaultToolkit().getImage(
				getClass().getResource("logo_16.png"));
		PopupMenu popup = new PopupMenu();
		MenuItem showItem = new MenuItem("Show");
		ActionListener listener = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				setVisible(true);
				setExtendedState(Frame.NORMAL);
				SystemTray.getSystemTray().remove(trayIcon);
			}
		};
		showItem.addActionListener(listener);
		popup.add(showItem);

		MenuItem exitItem = new MenuItem("Exit");
		exitItem.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				exit();
			}
		});

		popup.add(exitItem);

		// 根据image、提示、菜单创建TrayIcon
		this.trayIcon = new TrayIcon(image, "HisMisControl", popup);
		// 给TrayIcon添加事件监听器
		this.trayIcon.addActionListener(listener);
	}

	private void exit() {
		int ret = JOptionPane.showConfirmDialog(this, "您是否确认退出？", "退出确认",
				JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE,
				systemIcon);

		if (JOptionPane.YES_OPTION == ret) {
			dispose();
			System.exit(0);
		}
	}

	private JMenuItem viewMenuItem;
	private JMenuItem clearMenuItem;

	private void initIcons() {

		systemIcon = new ImageIcon(Toolkit.getDefaultToolkit().getImage(
				getClass().getResource("logo_32.png")));

	}

	private void initMenuItems() {

		viewMenuItem = new JMenuItem("查看记录", new ImageIcon(Toolkit
				.getDefaultToolkit().getImage(
						getClass().getResource("view.png"))));
		viewMenuItem.setFont(getResultFont());

		viewMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				TreePath path = resultTree.getSelectionModel()
						.getSelectionPath();

				DefaultMutableTreeNode c = (DefaultMutableTreeNode) resultTree
						.getLastSelectedPathComponent();

				// get the jobResultInfo

				for (int i = path.getPathCount(); i > 2; i--) {
					c = (DefaultMutableTreeNode) c.getParent();
				}

				if (c.getUserObject() instanceof JobResultInfo) {
					// use desktop to open the report file
					try {
						Desktop.getDesktop().open(
								JobResultReport.getReportFile((JobResultInfo) c
										.getUserObject()));
					} catch (IOException e1) {
						JOptionPane.showMessageDialog(MainFrame.this,
								e1.toString(), "错误", JOptionPane.ERROR_MESSAGE,
								systemIcon);
					}

				}

			}
		});

		clearMenuItem = new JMenuItem("清空记录", new ImageIcon(Toolkit
				.getDefaultToolkit().getImage(
						getClass().getResource("clear.png"))));
		clearMenuItem.setFont(getResultFont());
		clearMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				int ret = JOptionPane.showConfirmDialog(MainFrame.this,
						"您是否确认清空记录？", "清空记录确认", JOptionPane.YES_NO_OPTION,
						JOptionPane.INFORMATION_MESSAGE, systemIcon);

				if (JOptionPane.YES_OPTION == ret) {
					root.removeAllChildren();
					resultTree.updateUI();
				}

			}
		});
	}

	private void changeStatus(int status) {

		switch (status) {
			case STATUS_FREE :

				lab_status.setText("空闲中...");
				lab_status.setForeground(Color.BLACK);
				break;

			case STATUS_RUNNING :
				lab_status.setText("执行中...");
				lab_status.setForeground(Color.ORANGE);
				break;

			case STATUS_STOP :
				lab_status.setText("已停止");
				lab_status.setForeground(Color.RED);
				progressBar.setValue(0);
				break;

		}

	}
}
